﻿#ifndef DOU_GPU_INSTANCING_SKINNING_MESH
#define DOU_GPU_INSTANCING_SKINNING_MESH

// 2 个动画动作混合的顶点算法
#define SkinBlend(pos0, pos1, crossFadeBlend) pos1.xyz + (pos0.xyz - pos1.xyz) * crossFadeBlend

// 采样动画贴图
TEXTURE2D(_AnimTex);
SAMPLER(sampler_AnimTex);

struct AnimData
{
    // 当前剪辑播放的索引
    int playingIndex;
    // 是否处于动作混合中
    int isCrossBlending;
    // 上一个剪辑播放的索引
    int lastPlayingIndex;
    // 如果处于混合中则当前混合的百分比
    float crossFadeProgress;
};

float frameWidth; // 动画贴图的宽度倒数
float frameHeight; // 动画贴图的高度倒数
StructuredBuffer<float4x4> transBuf; // 定义接收的buff
StructuredBuffer<AnimData> animDataBuf; // 定义接收的buff

// 根据当前的帧数和骨骼索引，获取模型空间下的该骨骼对应矩阵
float4x4 GetAnimTrans(const int frameIndex, const float boneIndex)
{
    float4x4 trans;
    const float uvFrame = (frameIndex + 0.5) * frameWidth;
    const float uvBone = boneIndex * 3 + 0.5;
    float2 uv = float2(uvFrame, uvBone * frameHeight);
    trans[0] = SAMPLE_TEXTURE2D_LOD(_AnimTex, sampler_AnimTex, uv, 0);
    uv.y = (uvBone + 1) * frameHeight;
    trans[1] = SAMPLE_TEXTURE2D_LOD(_AnimTex, sampler_AnimTex, uv, 0);
    uv.y = (uvBone + 2) * frameHeight;
    trans[2] = SAMPLE_TEXTURE2D_LOD(_AnimTex, sampler_AnimTex, uv, 0);
    trans[3] = float4(0, 0, 0, 1);
    return trans;
}

// 输入顶点位置，获取该顶点在指定帧下的世界坐标
float4 GetAnimPosition(float4x4 trans, const float4 input, const int frameIndex, const float4 boneIndices, const float4 boneWeights)
{
    const float4x4 bone1Trans = GetAnimTrans(frameIndex, boneIndices[0]);
    const float4x4 bone2Trans = GetAnimTrans(frameIndex, boneIndices[1]);
    const float4x4 bone3Trans = GetAnimTrans(frameIndex, boneIndices[2]);
    const float4x4 bone4Trans = GetAnimTrans(frameIndex, boneIndices[3]);
    const float4 bone1WeightPos = mul(bone1Trans, input) * boneWeights[0];
    const float4 bone2WeightPos = mul(bone2Trans, input) * boneWeights[1];
    const float4 bone3WeightPos = mul(bone3Trans, input) * boneWeights[2];
    const float4 bone4WeightPos = mul(bone4Trans, input) * boneWeights[3];
    const float4 result = bone1WeightPos + bone2WeightPos + bone3WeightPos + bone4WeightPos;
    return mul(trans, result);
}

#endif